/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proxy;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;

/**
 *
 * @author Hue
 */
public class VPN implements Runnable, ClipboardOwner {
    private int currentIndex = 0;
    private long lastRun = -1;
    private Properties config;
    private Properties clients;
    private ArrayList<String> alServers;
    private ArrayList<String> alDone;
    private ArrayList<String> alWaiting;
    
    public VPN(Properties cf, String clientFile, String vpnServerFile) throws IOException {
        ArrayList<String> list = new OtherServers(vpnServerFile).get();
        //for(int i=0;i<100; i++) {
            addServers(list);
        //}
        //alServers = new ArrayList<>();
        //alServers.add("localhost");
        alDone = new ArrayList<String>();
                
        config = cf;
        
        //debug [
        System.out.println("alServers.size(): " + alServers.size());
        //System.out.println(config);
        //]
        clients = new Properties();
        FileInputStream inn = new FileInputStream(clientFile);
        clients.load(inn);
        inn.close();
        
        alWaiting = new ArrayList<String>();
    }
    
    public void getLocalIp() {
        alDone.add(getIp());
    }
    
    public int exec(String command) throws IOException {
        Process p = Runtime.getRuntime().exec(command);
        SystemOut(p.getInputStream());

        return p.exitValue();
    }
    
    public void SystemOut(InputStream in) throws IOException {
        int nByte;
        final byte[] buff = new byte[1024*1024];
        while((nByte = in.read(buff)) > 0) {
            System.out.write(buff,0, nByte);
        }
        in.close();
    }
    
    public String checkIp() {
        try {
            String login = config.getProperty("login");
            String pwd = config.getProperty("pwd");
            int iReturn = exec("rasdial Test " + login + " " + pwd);
            if(iReturn != 0) {
                return null;
            }
        }
        catch(Exception ex) {
            System.out.println("checkIp:" + ex);
            return null;
        }
        sleep(3000);

        String ip = getIp();
        if(ip != null) {
            if(alDone.contains(ip)) {
                return null;
            }
            else {
                alDone.add(ip);
                return ip;
            }
        }
        else {
            return null;
        }
    }
    
    @Override
    public void run() {
        try {
            Thread.sleep(OpenURL.WAIT * 60000);
        }
        catch(Exception ex) {
            //ignore
        }
        process();
        new Thread(new AutoCheck(this)).start();
    }
    
    public void process() {
        Robot robot;
        try {
            robot = new Robot();
        }
        catch (AWTException ex) {
            System.out.println("VPN.run: " + ex);
            return;
        }
        OpenURL.clients = clients;
        while(openVPN(robot) == null) {
            continue;
        }
        OpenURL.REMOTE_SERVER = "http://adf.ly";
        sendIpToClients();
        lastRun = System.currentTimeMillis();
    }
    
    public long getLastRun() {
        return lastRun;
    }
    
    private String getNextServerIP() {
        if(currentIndex < 0 || currentIndex >= alServers.size()) {
            currentIndex = 0;
        }
        return alServers.get(currentIndex++);
    }
    
    private void sendIpToClients() {
        alWaiting.clear();
        Enumeration e = clients.keys();
        while(e.hasMoreElements()) {
            String key = (String) e.nextElement();
            String clientIP = clients.getProperty(key);
            alWaiting.add(clientIP);
            sendIP(clientIP);
        }
    }
    
    private void sendIP(String clientIP) {
        try {
            URL url = new URL("http://" + clientIP + ":8080/AutoView.jsp");
            InputStream in = url.openStream();
            in.read();
            in.close();
        }
        catch(Exception ex) {
            System.out.println(ex);
            alWaiting.remove(clientIP);
        }
    }
    
    public void viewDone(String clientIP) {
        while(alWaiting.remove(clientIP)) {
            continue;
        }
    }
    
    public boolean isAllFinished() {
        return alWaiting.isEmpty();
    }
    
    private void addServers(ArrayList<String> list) {
        if(alServers == null) {
            alServers = new ArrayList<String>();
        }
        alServers.addAll(list);
    }

    private void disconnect() {
        try {
            exec("rasdial Test /DISCONNECT");
        }
        catch(IOException ex) {
            System.out.println("exec:" + ex);
        }
    }
    
    private String openVPN(Robot robot) {
        for(int i=0; i<2; i++) {
            disconnect();
            sleep(2000);
        }
        String ip = getNextServerIP();
        //open network dialog
        doubleClick(robot, "vpn");
        //properties
        leftClick(robot, "vpn_properties");
        //paste
        setClipboardContents(ip);
        robot.keyPress(KeyEvent.VK_CONTROL);
        robot.keyPress(KeyEvent.VK_V);
        robot.keyRelease(KeyEvent.VK_V);
        robot.keyRelease(KeyEvent.VK_CONTROL);
        //ok (properties)
        leftClick(robot, "vpn_ok");
        //cancel (network dialog)
        leftClick(robot, "vpn_cancel");
        //connect (network dialog)
        //leftClick(robot, "vpn_connect");
        sleep(2000);
        return checkIp();
    }
    
    private int[] parsePoint(String key) {
        String s = config.getProperty(key);
        if(s == null || s.isEmpty()) {
            return null;
        }
        try {
            String[] arr = s.split(":");
            return new int[] {Integer.parseInt(arr[0]), Integer.parseInt(arr[1])};
        }
        catch(Exception ex) {
            System.out.println(ex + ": " + s);
        }
        return null;
    }
    
    public void leftClick(Robot robot, String key) {
        int[] p = parsePoint(key);
        if(p != null) {
            leftClick(robot, p[0], p[1]);
        }
    }
    
    public void doubleClick(Robot robot, String key) {
        int[] p = parsePoint(key);
        if(p != null) {
            doubleClick(robot, p[0], p[1]);
        }
    }
    
    public void rightClick(Robot robot, String key) {
        int[] p = parsePoint(key);
        if(p != null) {
            rightClick(robot, p[0], p[1]);
        }
    }

    public void leftClick(Robot robot, int x, int y) {
        mouseClick(robot, x, y, 1, false);
    }

    public void rightClick(Robot robot, int x, int y) {
        mouseClick(robot, x, y, 1, true);
    }

    public void doubleClick(Robot robot, int x, int y) {
        mouseClick(robot, x, y, 2, false);
    }

    private void mouseClick(Robot robot, int x, int y, int click, boolean isRightClick) {
        try {
            robot.mouseMove(x, y);
            int button = InputEvent.BUTTON1_MASK;
            if(isRightClick) {
                button = InputEvent.BUTTON3_MASK;
            }
            robot.mousePress(button);
            robot.mouseRelease(button);
            if(click == 2) {
                robot.mousePress(button);
                robot.mouseRelease(button);
            }
            Thread.sleep(1000);
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    public void setClipboardContents(String aString) {
        StringSelection stringSelection = new StringSelection(aString);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, this);
    }
    
    public void sleep(long millis) {
        try {
            Thread.sleep(millis);
        }
        catch(Exception ex) {
            System.out.println(ex);
        }
    }
    
    public String getIp() {
        try {
            URL url = new URL("http://users9.nofeehost.com/group5vn/ip.asp");
            URLConnection con = url.openConnection();
            int connectTimeout = 10000;
            con.setConnectTimeout(connectTimeout);
            InputStream in = con.getInputStream();
            byte[] data = readData(in);
            String content = new String(data);
            in.close();

            return content;
        }
        catch(Exception ex) {
            System.out.println("getIp: " + ex);
        }
        return null;
    }
    
    private byte[] readData(final InputStream in) throws java.io.IOException {
        final ByteArrayOutputStream baOut = new ByteArrayOutputStream();
        int nByte;
        final byte[] buff = new byte[1024*1024];
        while((nByte = in.read(buff)) > 0) {
            baOut.write(buff,0, nByte);
        }
        final byte[] data = baOut.toByteArray();
        baOut.close();
        
        return data;
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
        System.out.println("lostOwnership!");
    }
}
